package com.hcl.orm.core.dialect.handler;

import com.hcl.orm.core.annotation.DBType;
import com.hcl.orm.core.dialect.handler.func.FuncDialectHandler;
import com.hcl.orm.core.dialect.handler.page.QueryPageDialectHandler;
import com.hcl.orm.core.exception.NotSupportDbTypeException;
import com.hcl.orm.core.exception.OrmException;
import com.hcl.orm.core.executor.DataSourceTypeLookup;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author hucl
 * @projectName jim-orm
 * @description: Sql方言处理器工厂类
 * @date 2021/5/2015:27
 */
@Component
public class SqlDialectHandlerFactory implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    private static Map<DBType, AbstractDialectHandler> dialectHandlerMap = new ConcurrentHashMap<>();
    @Resource
    private TargetScriptHandler targetScriptHandler;

    @Resource
    private SimpleDialectHandler simpleDialectHandler;


    public AbstractDialectHandler createDialectHandler(DataSourceTypeLookup lookup, String pkgName) {
        DBType dbType = lookup.getDataSourceType(pkgName);
        if (dialectHandlerMap.containsKey(dbType)) {
            return dialectHandlerMap.get(dbType);
        } else {
            targetScriptHandler.setDbType(dbType);
            targetScriptHandler.setNextHandler(simpleDialectHandler);

            Map<String, FuncDialectHandler> funBeanMaps = this.applicationContext.getBeansOfType(FuncDialectHandler.class);
            FuncDialectHandler funcDialectHandler = funBeanMaps.entrySet().stream().filter(i -> i.getValue().getTargetDB().contains(dbType))
                    .findFirst().orElseThrow(() ->
                            new NotSupportDbTypeException("can not find the funcDialectHandler.")
                    ).getValue();
            if (funcDialectHandler != null) {
                simpleDialectHandler.setNextHandler(funcDialectHandler);
            } else {
                throw new OrmException("funcDialectHandler can not be null");
            }
            Map<String, QueryPageDialectHandler> pageBeanMaps = this.applicationContext.getBeansOfType(QueryPageDialectHandler.class);

            QueryPageDialectHandler pageDialectHandler = pageBeanMaps.entrySet().stream()
                    .filter(i -> i.getValue().getTargetDB().contains(dbType))
                    .findFirst().orElseThrow(() ->
                            new NotSupportDbTypeException("can not find the queryPageDialectHandler.")
                    ).getValue();
            if (pageDialectHandler != null) {
                funcDialectHandler.setNextHandler(pageDialectHandler);
            } else {
                throw new OrmException("queryPageDialectHandler can not be null");
            }
            dialectHandlerMap.putIfAbsent(dbType, targetScriptHandler);
            return targetScriptHandler;
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
